home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / System 7.0 Samples / Kibitz / BoardSlider.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-21  |  15.7 KB  |  590 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:     Kibitz
  5. ** File:        BoardSlider.c
  6. ** Written by:  Eric Soldan
  7. **
  8. ** Copyright © 1990-1991 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* This is a custom slider for Kibitz.  It sends AppleEvents to the opponent,
  13. ** if there is one, so that the remote board is also scrolled.  It sends a
  14. ** maximum of 1 a second, so that they will be able to be processed without
  15. ** stacking up at the other end.
  16. **
  17. ** There is a custom cdef for this code.  All it does is jump to this code.
  18. ** There is a really good reason for this, which is most obscure.  It is
  19. ** possible that, when you choose an opponent machine, you choose your own
  20. ** machine.  This is fully supported in Kibitz.  As a matter of fact, only
  21. ** theMakeTarget code "knows" that it is the same machine.  The rest of the
  22. ** application is completely ignorant of this fact.  When the user clicks
  23. ** on the slider, the control manager locks down the cdef, and then calls it.
  24. ** When the custom cdef returns to the control manager, the cdef is unlocked.
  25. ** This all seems very reasonable.  However, in the case that you are sending
  26. ** a game to the same machine, I send an AppleEvent, which causes an update
  27. ** on the slider.  This update is handled by the control manager calling the
  28. ** cdef.  Of course, it locks it down, and then when the control manager is
  29. ** returned to, it unlocks it.  BUT WAIT!!  We are still tracking the slider
  30. ** that caused the AppleEvent to be sent, which in turn caused the slider of
  31. ** another window to update.  This is true.  It is also true that the cdef
  32. ** is now UNLOCKED!  And with AppleEvents using memory in a healthy way, it
  33. ** is very probable that the cdef will  move.  It isn't a good idea to rts
  34. ** to code that has moved.  This is why the cdef jumps to the code in the
  35. ** application.  We never return to the (potentially unlocked) cdef.  We
  36. ** return straight to the control manager.  Ugly problem, huh?
  37. */
  38.  
  39.  
  40.  
  41. /*****************************************************************************/
  42.  
  43.  
  44.  
  45. #define kCapHeight        11
  46. #define kThumbHeight    7
  47. #define kThumbOffset    12
  48. #define kSliderWidth    13
  49.  
  50. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  51. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  52. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  53.  
  54. #ifndef __RESOURCES__
  55. #include <Resources.h>
  56. #endif
  57.  
  58. #ifndef __TOOLUTILS__
  59. #include <ToolUtils.h>
  60. #endif
  61.  
  62. #ifndef __UTILITIES__
  63. #include <Utilities.h>
  64. #endif
  65.  
  66.  
  67.  
  68. /*****************************************************************************/
  69.  
  70.  
  71.  
  72. typedef struct cdefRsrcJMP {
  73.     long    moveInst;
  74.     long    jsrInst;
  75.     short    jmpInst;
  76.     long    jmpAddress;
  77. } cdefRsrcJMP;
  78. typedef cdefRsrcJMP *cdefRsrcJMPPtr, **cdefRsrcJMPHndl;
  79.  
  80. static void            BoardDrawIcon(Handle iconHndl, short hloc, short vloc);
  81. static pascal long    BoardSliderCtl(short varCode, ControlHandle ctl, short msg, long parm);
  82. static void            BoardSliderUpdate(ControlHandle ctl, short hiliteCap);
  83. static Rect            CalcSliderRect(ControlHandle ctl);
  84. static void            TrackSlider(ControlHandle ctl, Point origMouseLoc);
  85.  
  86.  
  87.  
  88. /*****************************************************************************/
  89.  
  90.  
  91.  
  92. /* Given a file reference, adjust the slider to reflect the position
  93. ** of the chessboard.
  94. */
  95.  
  96. #pragma segment Controls
  97. void    AdjustGameSlider(FileRecHndl frHndl)
  98. {
  99.     ControlHandle    ctl;
  100.     short            val, max;
  101.     WindowPtr        oldPort;
  102.  
  103.     ctl = (*frHndl)->doc.gameSlider;
  104.     val = (*frHndl)->doc.gameIndex;
  105.     max = (*frHndl)->doc.numGameMoves;
  106.         /* Get the info we need. */
  107.  
  108.     (*ctl)->contrlMax   = max;
  109.     (*ctl)->contrlValue = val;
  110.     oldPort = SetFilePort(frHndl);
  111.     BoardSliderUpdate(ctl, -1);
  112.         /* Change the slider value and show the result. */
  113.  
  114.     SetPort(oldPort);
  115. }
  116.  
  117.  
  118.  
  119. /*****************************************************************************/
  120.  
  121.  
  122.  
  123. #pragma segment Controls
  124. ControlHandle    BoardSliderNew(WindowPtr window)
  125. {
  126.     WindowPtr        oldPort;
  127.     FileRecHndl        frHndl;
  128.     Rect            boardRect;
  129.     ControlHandle    sliderCtl;
  130.     cdefRsrcJMPHndl    cdefRsrc;
  131.  
  132.     GetPort(&oldPort);
  133.     SetPort(window);
  134.  
  135.     frHndl = (FileRecHndl)GetWRefCon(window);
  136.  
  137.     boardRect = BoardRect();
  138.     boardRect.left    = boardRect.right + 6;
  139.     boardRect.right   = boardRect.left + 13;
  140.     boardRect.top    += 34;
  141.     boardRect.bottom -= 39;
  142.  
  143.     cdefRsrc = (cdefRsrcJMPHndl)GetResource('CDEF', rSliderCtl);
  144.     (*cdefRsrc)->jmpAddress = (ProcPtr)BoardSliderCtl;
  145.     sliderCtl = NewControl(window, &boardRect, nil, true, 0, 0, 0,
  146.                            rSliderCtl * 16, (long)frHndl);
  147.  
  148.     return(sliderCtl);
  149. }
  150.  
  151.  
  152.  
  153. /*****************************************************************************/
  154.  
  155.  
  156.  
  157. #pragma segment Controls
  158. pascal long    BoardSliderCtl(short varCode, ControlHandle ctl, short msg, long parm)
  159. {
  160. #pragma unused (varCode)
  161.  
  162.     Rect            viewRect;
  163.     static Point    lastClick;
  164.  
  165.     viewRect = (*ctl)->contrlRect;
  166.  
  167.     switch (msg) {
  168.         case drawCntl:
  169.             BoardSliderUpdate(ctl, -1);
  170.             break;
  171.  
  172.         case testCntl:
  173.             if ((*ctl)->contrlHilite == 255) return(0);
  174.             if (!(*ctl)->contrlMax) return(0);
  175.             if (PtInRect(*(Point *)&parm, &viewRect)) {
  176.                 lastClick = *((Point *)&parm);
  177.                 return(inThumb);
  178.             }        /* Everything is the thumb.  The "thumb" routine will figure
  179.                     ** out what part it is.  Since this is a very specific control,
  180.                     ** we can get away with this simplification. */
  181.             return(0);
  182.  
  183.         case calcCRgns:
  184.         case calcCntlRgn:
  185.             if (msg == calcCRgns) parm &= 0x00FFFFFF;
  186.             RectRgn((RgnHandle)parm, &viewRect);
  187.             break;
  188.  
  189.         case initCntl:
  190.             break;
  191.  
  192.         case dispCntl:
  193.             break;
  194.  
  195.         case posCntl:
  196.             break;
  197.  
  198.         case thumbCntl:
  199.             TrackSlider(ctl, lastClick);
  200.             break;
  201.  
  202.         case dragCntl:
  203.             return(true);
  204.  
  205.         case autoTrack:
  206.             break;
  207.     }
  208.  
  209.     return(0);
  210. }
  211.  
  212.  
  213.  
  214. /*****************************************************************************/
  215.  
  216.  
  217.  
  218. #pragma segment Controls
  219. void    BoardSliderUpdate(ControlHandle ctl, short hiliteCap)
  220. {
  221.     Rect        ctlRect, workRect, sliderRect;
  222.     FileRecHndl    frHndl;
  223.     Boolean        active;
  224.     short        i, j, thumbColor;
  225.     RgnHandle    origClipRgn, clipRgn, workRgn;
  226.     Handle        icons[7];
  227.  
  228.     /* We use color icons here for the various slider parts.  This is so that we
  229.     ** can take advantage of the depth of monitors.  I use icons here so that I
  230.     ** can do a single plot of an icon if the delta of the thumb is -12 to 12.
  231.     ** (The thumb is in the center of an icon, and 12 pixels above and below the
  232.     ** icon, I have slider bar.  Use RedEdit to check it out.)  This technique
  233.     ** gives a very smooth appearance when the thumb slides.  There is no flash.
  234.     ** For deltas greater than +-12, I redraw the slider without the thumb, and
  235.     ** then draw the thumb in the new position.  Since the thumb is moving a lot
  236.     ** anyway, this doesn't show up as a flicker.  There is no overlap in the
  237.     ** old and new positions for a big delta. */
  238.  
  239.     ctlRect = (*ctl)->contrlRect;
  240.     frHndl  = (FileRecHndl)GetCRefCon(ctl);
  241.  
  242.     for (i = 0; i < 7; i++)
  243.         if (gQDVersion)
  244.             icons[i] = (Handle)GetCIcon(i + rSliderBase);
  245.         else
  246.             icons[i] = GetResource('ICN#', i + rSliderBase);
  247.                 /* Using color icons is a pain, if you want to support different
  248.                 ** versions of QuickDraw.  Oh well... */
  249.  
  250.     origClipRgn = NewRgn();
  251.     GetClip(origClipRgn);
  252.  
  253.     clipRgn = NewRgn();
  254.  
  255.     for (i = 0; i < 2; i++) {        /* Draw the arrow parts first. */
  256.         j = i;
  257.         if (hiliteCap == i) j += 5;
  258.         workRect = ctlRect;
  259.         if (!i)
  260.             workRect.bottom = workRect.top + kCapHeight;
  261.         else
  262.             workRect.top = workRect.bottom - kCapHeight;
  263.         RectRgn(clipRgn, &workRect);
  264.         SetClip(clipRgn);
  265.             /* Clip out the area outside the arrow part. */
  266.         BoardDrawIcon(icons[j], workRect.left, workRect.top);
  267.             /* Draw the arrow part. */
  268.     }
  269.  
  270.     ctlRect.top    += kCapHeight;
  271.     ctlRect.bottom -= kCapHeight;
  272.     RectRgn(clipRgn, &ctlRect);
  273.     SetClip(clipRgn);
  274.         /* Clip out everything except the slider bar area. */
  275.  
  276.     active  = ((*ctl)->contrlOwner == FrontWindow());
  277.     if ((*ctl)->contrlHilite == 255) active = false;
  278.     if (!(*ctl)->contrlMax) active = false;
  279.  
  280.     if (active) {        /* If control active, draw the thumb. */
  281.         sliderRect = CalcSliderRect(ctl);
  282.         thumbColor = (((*ctl)->contrlValue & 0x01) ^ (*frHndl)->doc.startColor);
  283.         BoardDrawIcon(icons[3 + thumbColor],
  284.                       sliderRect.left, sliderRect.top - kThumbOffset);
  285.         workRgn = NewRgn();
  286.         RectRgn(workRgn, &sliderRect);
  287.         DiffRgn(clipRgn, workRgn, clipRgn);
  288.         SetClip(clipRgn);
  289.         DisposeRgn(workRgn);
  290.             /* Now that the thumb is drawn, protect it by clipping it out. */
  291.     }
  292.  
  293.     for (i = ctlRect.top; i < ctlRect.bottom; i += 32)
  294.         BoardDrawIcon(icons[2], ctlRect.left, i);
  295.             /* Draw the slider bar portion. */
  296.  
  297.     /* It is now completely drawn.  Clean up and get out. */
  298.  
  299.     SetClip(origClipRgn);
  300.     DisposeRgn(clipRgn);
  301.     DisposeRgn(origClipRgn);
  302.  
  303.     if (gQDVersion)
  304.         for (i = 0; i < 7; i++)
  305.             DisposCIcon((CIconHandle)icons[i]);
  306. }
  307.  
  308.  
  309.  
  310. /*****************************************************************************/
  311.  
  312.  
  313.  
  314. #pragma segment Controls
  315. void    BoardDrawIcon(Handle iconHndl, short hloc, short vloc)
  316. {
  317.     Rect    iconRect;
  318.  
  319.     iconRect.right  = (iconRect.left = hloc) + 32;
  320.     iconRect.bottom = (iconRect.top  = vloc) + 32;
  321.  
  322.     if (gQDVersion)
  323.         PlotCIcon(&iconRect, (CIconHandle)iconHndl);
  324.     else
  325.         PlotIcon(&iconRect, iconHndl);
  326. }
  327.  
  328.  
  329.  
  330. /*****************************************************************************/
  331.  
  332.  
  333.  
  334. #pragma segment Controls
  335. Rect    CalcSliderRect(ControlHandle ctl)
  336. {
  337.     Rect    ctlRect, sliderRect;
  338.     short    max, val;
  339.     long    calc;
  340.  
  341.     ctlRect = (*ctl)->contrlRect;
  342.     ctlRect.top    += kCapHeight;
  343.     ctlRect.bottom -= kCapHeight;
  344.     max = (*ctl)->contrlMax;
  345.     val = (*ctl)->contrlValue;
  346.  
  347.     calc = ctlRect.bottom - ctlRect.top - kThumbHeight;
  348.     calc *= val;
  349.     if (max) calc /= max;
  350.     sliderRect.top    = ctlRect.top + calc,
  351.     sliderRect.left   = ctlRect.left;
  352.     sliderRect.bottom = sliderRect.top + kThumbHeight;
  353.     sliderRect.right  = ctlRect.right;
  354.  
  355.     return(sliderRect);
  356. }
  357.  
  358.  
  359.  
  360. /*****************************************************************************/
  361.  
  362.  
  363.  
  364. #pragma segment Controls
  365. void    TrackSlider(ControlHandle ctl, Point origMouseLoc)
  366. {
  367.     Handle        icons[7];
  368.     WindowPtr    oldPort;
  369.     Rect        ctlRect, sliderRange, slopRect, sliderRect, capRect;
  370.     FileRecHndl    frHndl;
  371.     RgnHandle    origClipRgn, clipRgn, workRgn;
  372.     short        i, max, val, origGameIndex, ovloc, voffset, vloc, delta, hiliteCap;
  373.     Boolean        twoPlayer, hiliteOn;
  374.     long        origTick, tick, calc;
  375.     Point        lastMouseLoc, mouseLoc;
  376.  
  377.     /* Get everything we need set up. */
  378.  
  379.     origTick = tick = TickCount();
  380.  
  381.     for (i = 2; i < 5; i++)
  382.         if (gQDVersion)
  383.             icons[i] = (Handle)GetCIcon(i + rSliderBase);
  384.         else
  385.             icons[i] = GetResource('ICN#', i + rSliderBase);
  386.  
  387.     frHndl  = (FileRecHndl)GetCRefCon(ctl);
  388.     oldPort = SetFilePort(frHndl);
  389.     ctlRect = (*ctl)->contrlRect;
  390.  
  391.     origClipRgn = NewRgn();
  392.     GetClip(origClipRgn);
  393.  
  394.     clipRgn = NewRgn();
  395.     workRgn = NewRgn();
  396.  
  397.     origGameIndex = (*frHndl)->doc.gameIndex;
  398.     max = (*ctl)->contrlMax;
  399.  
  400.     twoPlayer  = (*frHndl)->doc.twoPlayer;
  401.     sliderRect = CalcSliderRect(ctl);
  402.  
  403.     /* That ought to be enough setup. */
  404.  
  405.     if (PtInRect(origMouseLoc, &sliderRect)) {    /* If they are on the thumb... */
  406.  
  407.         ctlRect.top    += kCapHeight;            /* Protect the arrow parts. */
  408.         ctlRect.bottom -= kCapHeight;
  409.         RectRgn(clipRgn, &ctlRect);
  410.         SetClip(clipRgn);
  411.  
  412.         sliderRange = ctlRect;                    /* Calc area thumb can move. */
  413.         sliderRange.bottom -= kThumbHeight;        /* Count height of thumb against range. */
  414.  
  415.         slopRect = sliderRange;                    /* Give the user some slop. */
  416.         InsetRect(&slopRect, -20, -20);
  417.  
  418.         lastMouseLoc = origMouseLoc;
  419.         voffset = lastMouseLoc.v - sliderRect.top;
  420.         ovloc   = lastMouseLoc.v - voffset;
  421.  
  422.         while (StillDown()) {
  423.  
  424.             if (tick + 30 < TickCount()) {        /* Send max 1 AppleEvent per 1/2 sec. */
  425.                 tick = TickCount();
  426.                 if (twoPlayer) SendGame(frHndl, kScrolling);
  427.             }
  428.  
  429.             GetMouse(&mouseLoc);
  430.             if (!EqualPt(mouseLoc, lastMouseLoc)) {        /* The mouse has moved. */
  431.  
  432.                 if (!PtInRect(mouseLoc, &slopRect)) mouseLoc = origMouseLoc;
  433.                     /* Outside slopRect, so snap back to the original position. */
  434.  
  435.                 vloc = mouseLoc.v - voffset;
  436.                 if (vloc < sliderRange.top)    vloc = sliderRange.top;
  437.                 if (vloc > sliderRange.bottom) vloc = sliderRange.bottom;
  438.                 delta = vloc - ovloc;
  439.                     /* The delta tells us how much the thumb moved. */
  440.  
  441.                 if (
  442.                     (delta < -((32 - kThumbHeight) / 2)) ||
  443.                     (delta >  ((32 - kThumbHeight) / 2))
  444.                 ) {
  445.                     for (i = ctlRect.top; i < ctlRect.bottom; i += 32)
  446.                         BoardDrawIcon(icons[2], ctlRect.left, i);
  447.                             /* The thumb moved too far for a single plot to cover
  448.                             ** up the old position, so clear the old thumb. */
  449.                 }
  450.  
  451.                 calc  = (max + 1) * (vloc - sliderRange.top);
  452.                     /* We use max + 1 because there is one more game
  453.                     ** move position than moves in the game.  This is
  454.                     ** because we can position in front of the first move,
  455.                     ** as well as after the last move.
  456.                     */
  457.  
  458.                 calc /= (sliderRange.bottom - sliderRange.top);
  459.                 val = calc;
  460.                 if (val > max) val = max;
  461.                 if (val < 0)   val = 0;
  462.                 BoardDrawIcon(icons[3 + ((val + (*frHndl)->doc.startColor) & 0x01)],
  463.                               ctlRect.left, vloc - kThumbOffset);
  464.                                     /* The thumb is now updated. */
  465.  
  466.                 SetClip(origClipRgn);
  467.                 RepositionBoard(frHndl, val, true);
  468.                     /* We set the clipRgn back to the original so the board
  469.                     ** can update.  (Pretty boring if it doesn't. */
  470.  
  471.                 SetClip(clipRgn);
  472.                     /* Back to our normally scheduled program... */
  473.  
  474.                 lastMouseLoc = mouseLoc;
  475.                 (*ctl)->contrlValue = val;
  476.                 ovloc = vloc;
  477.             }
  478.         }
  479.     }
  480.  
  481.     else {        /* We missed the thumb.  See if we hit an arrow part... */
  482.         delta = hiliteOn = 0;
  483.         capRect = ctlRect;
  484.         capRect.bottom = ctlRect.top + kCapHeight;
  485.         if (PtInRect(origMouseLoc, &capRect)) {
  486.             delta = -1;
  487.             hiliteCap = 0;
  488.         }
  489.         else {
  490.             capRect = ctlRect;
  491.             capRect.top = ctlRect.bottom - kCapHeight;
  492.             if (PtInRect(origMouseLoc, &capRect)) {
  493.                 delta = 1;
  494.                 hiliteCap = 1;
  495.             }
  496.         }
  497.  
  498.         if (delta) {    /* We hit an arrow, and there is a change to do... */
  499.             do {
  500.                 if (tick + 30 < TickCount()) {
  501.                     tick = TickCount();
  502.                     if (twoPlayer) SendGame(frHndl, kScrolling);
  503.                 }
  504.                 GetMouse(&mouseLoc);
  505.                 if (PtInRect(mouseLoc, &capRect)) {        /* Still in arrow... */
  506.                     val = (*ctl)->contrlValue + delta;
  507.                     if ((val >= 0) && (val <= max)) {    /* Still scrolling... */
  508.                         hiliteOn = true;
  509.                         (*ctl)->contrlValue = val;
  510.                         BoardSliderUpdate(ctl, hiliteCap);
  511.                         SetClip(origClipRgn);
  512.                         if (RepositionBoard(frHndl, val, true))
  513.                         SetClip(clipRgn);
  514.                     }
  515.                     else {        /* Scrolled as far as we can go, so unhilite arrow. */
  516.                         if (hiliteOn) {
  517.                             BoardSliderUpdate(ctl, -1);
  518.                             hiliteOn = false;
  519.                         }
  520.                     }
  521.                 }
  522.                 else {        /* Outside arrow, so unhilite it. */
  523.                     if (hiliteOn) {
  524.                         BoardSliderUpdate(ctl, -1);
  525.                         hiliteOn = false;
  526.                     }
  527.                 }
  528.  
  529.                 while ((StillDown()) && (origTick + 20 > TickCount()));
  530.                     /* Don't go too fast. */
  531.  
  532.             } while (StillDown());
  533.         }
  534.     }
  535.  
  536.     SetClip(origClipRgn);
  537.     DisposeRgn(workRgn);
  538.     DisposeRgn(clipRgn);
  539.     DisposeRgn(origClipRgn);
  540.  
  541.     if (twoPlayer) SendGame(frHndl, kResync);
  542.         /* Make sure that the result from the scroll isn't ignored.  The
  543.         ** opponent may ignore the events while we are scrolling, but not
  544.         ** when we are done. */
  545.  
  546.     BoardSliderUpdate(ctl, -1);
  547.         /* Snap the slider to a move position.  The user may have let go of the
  548.         ** slider at a position that doesn't map exactly to the game position. */
  549.  
  550.     if (gQDVersion)
  551.         for (i = 2; i < 5; i++)
  552.             DisposCIcon((CIconHandle)icons[i]);
  553.  
  554.     SetPort(oldPort);
  555. }
  556.  
  557.  
  558.  
  559. /*****************************************************************************/
  560.  
  561.  
  562.  
  563. #pragma segment Controls
  564. Boolean    RepositionBoard(FileRecHndl frHndl, short newPos, Boolean update)
  565. {
  566.     short        oldPos, delta;
  567.  
  568.     oldPos = (*frHndl)->doc.gameIndex;
  569.     if (newPos == oldPos) return(false);
  570.  
  571.     delta  = (newPos > oldPos) ? 1 : -1;
  572.         /* We need to walk the board forward or backward delta number of moves. */
  573.  
  574.     for (; oldPos != newPos; oldPos += delta)
  575.         MakeMove(frHndl, delta, 0, 0, false);
  576.             /* Walk the board position one half-move forward or backward. */
  577.  
  578.     if (update) {
  579.         ImageDocument(frHndl, true);
  580.         DrawButtonTitle(frHndl, (*frHndl)->doc.twoPlayer);
  581.         UpdateGameStatus(frHndl);
  582.             /* Show the new board position. */
  583.     }
  584.  
  585.     return(true);
  586. }
  587.  
  588.  
  589.  
  590.